package multiThread;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ProjectName java-sample
 * @PackageName multiThread
 * @ClassName CountDownLatchTest
 * @Description:
 * @author: Administrator
 * @Date: 2019/9/14 12:46
 * @Version 1.0
 */
public class CountDownLatchTest {
    // 模拟了100米赛跑，10名选手已经准备就绪，只等裁判一声令下。当所有人都到达终点时，比赛结束。
    public static void main(String[] args) throws InterruptedException {

        // 开始的倒数锁
        final CountDownLatch begin = new CountDownLatch(1);

        // 结束的倒数锁
        final CountDownLatch end = new CountDownLatch(10);

        // 十名选手 线程池
        final ExecutorService exec = Executors.newFixedThreadPool(10);

        for (int index = 0; index < 10; index++) {
            final int NO = index + 1;
            Runnable run = new Runnable() {
                public void run() {
                    try {
                        // 如果当前计数为零，则此方法立即返回。
                        // 等待 使当前线程在锁存器倒计数至零之前一直等待，除非线程被中断或超出了指定的等待时间
                        begin.await();
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("No."+ NO + " arrived");

                    } catch (InterruptedException e) {
                    } finally {
                        // 每个选手到达终点时，end就减一
                        //递减锁存器的计数，如果计数到达零，则释放所有等待的线程。如果当前计数大于零，则将计数减少。如果新的计数为零
                        // 出于线程调度目的，将重新启用所有的等待线程。 如果当前计数等于零，则不发生任何操作
                        end.countDown();
                    }
                }
            };
            /*1.execute提交的是Runnable类型的任务，而submit提交的是Callable或者Runnable类型的任务

            2.execute的提交没有返回值，而submit的提交会返回一个Future类型的对象

            3.execute提交的时候，如果有异常，就会直接抛出异常，而submit在遇到异常的时候，通常不会立马抛出异常，而是会将异常暂时存储起来，等待你调用Future.get()方法的时候，才会抛出异常*/
            exec.submit(run);
        }
        System.out.println("Game Start");
        // begin减一，开始游戏
        begin.countDown();
        // 等待end变为0，即所有选手到达终点
        end.await();
        System.out.println("Game Over");
        exec.shutdown();
    }
}
